package com.tongsys.server.config.security;

import com.tongsys.server.config.security.exception.MyAccessDeniedHanlerImpl;
import com.tongsys.server.config.security.exception.MyAuthenticationEntryPointImpl;
import com.tongsys.server.config.security.filter.JWTTokenFilter;
import com.tongsys.server.config.security.handler.AnonymousAuthenticationHandler;
import com.tongsys.server.config.security.handler.CustomerAccessDeniedHandler;
import com.tongsys.server.config.security.handler.LoginFailureHandler;
import com.tongsys.server.config.security.handler.LoginSuccessHandler;
import com.tongsys.server.config.security.service.MyUserDetailsService;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
@ApiModel("spring security配置类")
@EnableWebSecurity  //开启security的使用
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private LoginSuccessHandler loginSuccessHandler;
    @Resource
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private CustomerAccessDeniedHandler customerAccessDeniedHandler;
    @Resource
    private AnonymousAuthenticationHandler anonymousAuthenticationHandler;
    @Resource
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private JWTTokenFilter jwtTokenFilter;

    @Autowired
    public MyAccessDeniedHanlerImpl myAccessDeniedHanler;

    @Autowired
    public MyAuthenticationEntryPointImpl myAuthenticationEntryPoint;

    /**
     * 注入加密类
     * 指定加密方式
     * 用户密码加密存储
     * 创建  BCryptPasswordEncoder 注入容器
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @ApiOperation("处理登录认证配置")
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登录过程处理
        http.authorizeRequests()
                .antMatchers("/api/login").anonymous() //登录还是不登录都能访问
                .antMatchers("/api/hello").anonymous() //允许匿名访问，登录了不能访问
                .antMatchers("/api/user/page").hasAnyAuthority("test11")  //设置权限
                .anyRequest().authenticated() // //其他任何请求 都需要认证 登录
                .and()
                .csrf().disable()  //关闭 xss网络攻击
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)  //session 的策略配置//不创建session
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint)  //认证异常
                .accessDeniedHandler(myAccessDeniedHanler)   //权限异常
                .and()
                .cors()
                .and().formLogin().successHandler(loginSuccessHandler).failureHandler(loginFailureHandler);  //spring security 支持跨域请求        ;
        //把token 验证过滤器 添加到security 过滤器链中
        http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);

    }

    @ApiOperation("处理用户和密码")
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //获取用户信息并 对密码加密
        auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @ApiOperation("用于暴露 AuthenticationManager，暴露之后 用户在登录的时候，就能调用封装用户名和密码在 Authentication中 ")
    @Override
    @Bean  //向容器中注入  authentication，用于封装得到的用户数据 并进行返回
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
